﻿using blackhouse.BlackApart.Business;
using blackhouse.BlackApart.Business.Discounts;
using blackhouse.BlackApart.Business.Prices;
using blackhouse.BlackApart.Business.Reservations;
using blackhouse.BlackApart.Data.Caching;
using blackhouse.Data;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;

namespace blackhouse.Aparts.Web.Discounts {
    public class LastMinuteDiscount : IDiscount {

        #region Fields

        private Dictionary<int, List<LastMinuteData>> data;
        private NemoCache cache = new NemoCache(TimeSpan.FromMinutes(2), ConfigurationManager.AppSettings["MSSQLConnectionString"]);
        private AdoDataHelper dataHelper = new MsSqlAdoDataHelper(ConfigurationManager.AppSettings["MSSQLConnectionString"]);

        #endregion

        #region Methods

        public void Apply(Variant variant, DateTime arrivalDate, DateTime departureDate, int peoples) {
            IEnumerable<LastMinuteData> data = this.GetData(variant.GetGroups()[0].Id);
            this.ApplyLastMinuteDiscount(variant, arrivalDate, departureDate, data);
        }

        private void ApplyLastMinuteDiscount(Variant variant, DateTime arrivalDate, DateTime departureDate, IEnumerable<LastMinuteData> data) {
            if (data.Count() == 0) return;
            data = data.OrderByDescending(d => d.Days);
            if ((arrivalDate.Date - DateTime.Now.Date).TotalDays > data.First().Days) return; // Jak wpis z najdłuższym okresem się nie łapie to pozostałe tym bardziej się nie załapią
            Dictionary<DateTime, float> rabatForDays = new Dictionary<DateTime, float>();
            DateTime endD = departureDate.Date, crnD = DateTime.Now.Date, chd = arrivalDate.Date;
            while (chd < endD) {
                var q = from d in data where (chd - crnD).TotalDays < d.Days orderby d.Days select d; // kwestia dyskusyjna, czy powinno być < czy może <=
                rabatForDays.Add(chd, q.FirstOrDefault().Rabat);
                chd = chd.AddDays(1);
            }
            float avgRabatValue = rabatForDays.Values.Average();
            if (avgRabatValue != 0) {
                IPriceRabat lastminuteRabat = Factory.Instance().GetPriceRabat("lastminute");
                if (lastminuteRabat != null) {
                    avgRabatValue = (float)Math.Round((double)avgRabatValue, 0);
                    lastminuteRabat.OverrideRabatValue(avgRabatValue);
                    variant.Price.ApplyPriceRabat(lastminuteRabat);
                }
            }
        }

        public void SetXmlConfiguration(System.Xml.XmlElement configurationNode) {

        }

        private IEnumerable<LastMinuteData> GetData(int apartmentTypeId) {
            if (data == null)
                this.data = this.GetDbData();
            if (this.data.ContainsKey(apartmentTypeId))
                return this.data[apartmentTypeId];
            else
                return new LastMinuteData[0];
        }

        protected virtual Dictionary<int, List<LastMinuteData>> GetDbData() {
            cache.Reset();
            cache.SetKey("LastMinute");
            cache.SetDependencyTables("T374");
            Dictionary<int, List<LastMinuteData>> data = cache.GetData<Dictionary<int, List<LastMinuteData>>>();
            if (data == null) {
                data = new Dictionary<int, List<LastMinuteData>>();
                this.dataHelper.Reset();
                this.dataHelper.Query = "SELECT * FROM T374 WHERE del=0";
                IDataReader reader = this.dataHelper.Execute();
                while (reader.Read()) {
                    int apartmentTypeId = Convert.ToInt32(reader["typ_apartamentu"]);
                    LastMinuteData lfData = new LastMinuteData();
                    lfData.Days = Convert.ToInt32(reader["do_ilu_last"]);
                    lfData.Rabat = Convert.ToSingle(reader["rabat"]);
                    if (!data.ContainsKey(apartmentTypeId))
                        data.Add(apartmentTypeId, new List<LastMinuteData>());
                    data[apartmentTypeId].Add(lfData);
                }
                reader.Close();
                cache.SetCaching(data);
            }
            return data;
        }

        #endregion

        #region Struct

        protected struct LastMinuteData {
            public int Days;
            public float Rabat;
        }

        #endregion

    }
}